﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Xml.XPath;

namespace Skybrud.UmbExt.UniversalMediaPicker.Providers.Issuu
{
    public class IssuuService
    {
        private string IssuuUrl = "http://api.issuu.com/1_0?";

        #region Constructor
        public IssuuService(string apikey, string apisecret)
        {
            APIKey = apikey;
            APISecret = apisecret;
        }
        #endregion


        #region Public methods
        /// <summary>
        /// Returns a Issuu Document
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public IssuuDoc GetDoc(string id)
        {
            var url = BuildIssuuDocumentUrl();

            HttpWebRequest req = WebRequest.Create(url) as HttpWebRequest;
            XPathDocument docNav;

            using (HttpWebResponse resp = req.GetResponse() as HttpWebResponse)
            {
                StreamReader reader = new StreamReader(resp.GetResponseStream());

                docNav = new XPathDocument(reader);
            }

            XPathNavigator nav;
            XPathNodeIterator nodeIter;

            nav = docNav.CreateNavigator();

            nodeIter = nav.Select("/rsp/result/child::* [@documentId = '" + id.ToString() + "']");

            nodeIter.MoveNext();

            var issuuDoc = new IssuuDoc
            {
                Access = nodeIter.Current.GetAttribute("access", ""),
                Description = nodeIter.Current.GetAttribute("description", ""),
                DocumentId = nodeIter.Current.GetAttribute("documentId", ""),
                Folders = CreateList(nodeIter.Current.SelectDescendants("folder", "", false), "id"),
                Name = nodeIter.Current.GetAttribute("name", ""),
                OrgDocName = nodeIter.Current.GetAttribute("orgDocName", ""),
                OrgDocType = nodeIter.Current.GetAttribute("orgDocType", ""),
                Origin = nodeIter.Current.GetAttribute("origin", ""),
                PageCount = nodeIter.Current.GetAttribute("pageCount", ""),
                PublishDate = nodeIter.Current.GetAttribute("publishDate", ""),
                State = nodeIter.Current.GetAttribute("state", ""),
                Tags = CreateList(nodeIter.Current.SelectDescendants("tag", "", false), "value"),
                Title = nodeIter.Current.GetAttribute("title", ""),
                Type = nodeIter.Current.GetAttribute("type", ""),
                Username = nodeIter.Current.GetAttribute("username", ""),
            };

            return issuuDoc;
        }

        /// <summary>
        /// Returns a collection of all public Issuu documents
        /// </summary>
        /// <returns></returns>
        public Collection<IssuuDoc> GetDocs()
        {
            var returnCol = new Collection<IssuuDoc>();
            var url = BuildIssuuDocumentUrl();
            HttpWebRequest req = WebRequest.Create(url) as HttpWebRequest;
            XPathDocument docNav;

            using (HttpWebResponse resp = req.GetResponse() as HttpWebResponse)
            {
                StreamReader reader = new StreamReader(resp.GetResponseStream());

                docNav = new XPathDocument(reader);
            }

            XPathNavigator nav = docNav.CreateNavigator();
            XPathNodeIterator nodeIter = nav.Select("/rsp/result/child::*");

            while(nodeIter.MoveNext())
            {
                var issuuDoc = new IssuuDoc
                    {
                        Access = nodeIter.Current.GetAttribute("access", ""),
                        Description = nodeIter.Current.GetAttribute("description", ""),
                        DocumentId = nodeIter.Current.GetAttribute("documentId", ""),
                        Folders = CreateList(nodeIter.Current.SelectDescendants("folder", "", false), "id"),
                        Name = nodeIter.Current.GetAttribute("name", ""),
                        OrgDocName = nodeIter.Current.GetAttribute("orgDocName", ""),
                        OrgDocType = nodeIter.Current.GetAttribute("orgDocType", ""),
                        Origin = nodeIter.Current.GetAttribute("origin", ""),
                        PageCount = nodeIter.Current.GetAttribute("pageCount", ""),
                        PublishDate = nodeIter.Current.GetAttribute("publishDate", ""),
                        State = nodeIter.Current.GetAttribute("state", ""),
                        Tags = CreateList(nodeIter.Current.SelectDescendants("tag", "", false), "value"),
                        Title = nodeIter.Current.GetAttribute("title", ""),
                        Type = nodeIter.Current.GetAttribute("type", ""),
                        Username = nodeIter.Current.GetAttribute("username", ""),
                        ViewCount = nodeIter.Current.GetAttribute("viewCount", "")
                    };
               
                returnCol.Add(issuuDoc);
            }

            return returnCol;
        }
        
        /// <summary>
        /// Returns a collection of all Issuu folders
        /// </summary>
        /// <returns></returns>
        public Collection<IssuuFolder> GetFolders()
        {
            var returnCol = new Collection<IssuuFolder>();
            var url = BuildIssuuFolderUrl();
            HttpWebRequest req = WebRequest.Create(url) as HttpWebRequest;
            XPathDocument docNav;

            using (HttpWebResponse resp = req.GetResponse() as HttpWebResponse)
            {
                StreamReader reader = new StreamReader(resp.GetResponseStream());

                docNav = new XPathDocument(reader);
            }

            XPathNavigator nav = docNav.CreateNavigator();
            XPathNodeIterator nodeIter = nav.Select("/rsp/result/child::*");

            while (nodeIter.MoveNext())
            {
                var issuuDoc = new IssuuFolder()
                {
                    FolderId = nodeIter.Current.GetAttribute("folderId", ""),
                    Created = nodeIter.Current.GetAttribute("created", ""),
                    Description = nodeIter.Current.GetAttribute("description", ""),
                    Items = Convert.ToInt32(nodeIter.Current.GetAttribute("items", "")),
                    Name = nodeIter.Current.GetAttribute("name", ""),
                    Username = nodeIter.Current.GetAttribute("username", ""),
                };

                returnCol.Add(issuuDoc);
            }

            return returnCol;
        }
        #endregion


        #region Private methods
        /// <summary>
        /// Builds a valid URL for requesting the IssuuAPI (documents)
        /// </summary>
        /// <returns></returns>
        private String BuildIssuuDocumentUrl()
        {
            const string actionString = "issuu.documents.list";
            const string accessString = "public";
            const string formatString = "xml";

            return IssuuUrl + "action=" + actionString + "&apiKey=" + APIKey + "&access=" + accessString + "&format=" + formatString + "&signature=" + CreateSignature(accessString, actionString, formatString);
        }

        /// <summary>
        /// Builds a valid URL for requesting the IssuuAPI (folders)
        /// </summary>
        /// <returns></returns>
        private string BuildIssuuFolderUrl()
        {
            const string actionString = "issuu.folders.list";
            const string formatString = "xml";

            return IssuuUrl + "action=" + actionString + "&apiKey=" + APIKey + "&format=" + formatString + "&signature=" +
                   CreateSignature(string.Empty, actionString, formatString);
        }

        /// <summary>
        /// Creates signature for Issuu REST request
        /// </summary>
        /// <param name="access"></param>
        /// <param name="action"></param>
        /// <param name="format"></param>
        /// <param name="responseParams"></param>
        /// <returns></returns>
        private String CreateSignature(string access, string action, string format)
        {
            string signatureString;

            if(string.IsNullOrEmpty(access))
            {
                signatureString = APISecret + "action" + action + "apiKey" + APIKey + "format" + format;
            } else
            {
                signatureString = APISecret + "access" + access + "action" + action + "apiKey" + APIKey + "format" + format;
            }

            return CalculateMD5Hash(signatureString);
        }

        /// <summary>
        /// Calculating MD5 hash
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static String CalculateMD5Hash(string input)
        {
            // step 1, calculate MD5 hash from input
            MD5 md5 = System.Security.Cryptography.MD5.Create();
            byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
            byte[] hash = md5.ComputeHash(inputBytes);

            // step 2, convert byte array to hex string
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < hash.Length; i++)
            {
                sb.Append(hash[i].ToString("X2"));
            }
            return sb.ToString().ToLower();
        }

        private static List<string> CreateList(XPathNodeIterator iterator, string attributeName)
        {
            var returnList = new List<String>();

            while(iterator.MoveNext())
            {
                returnList.Add(iterator.Current.GetAttribute(attributeName, ""));
            }

            return returnList;
        }

        #endregion


        #region properties
        //public ActionTypes Action { get; set; }
        //public AccessTypes Access { get; set; }
        //public List<ResponseParamsTypes> Parameters { get; set; }
        //public FormatTypes Format { get; set; }
        private String APIKey { get; set; }
        private String APISecret { get; set; }
        #endregion


        #region enums
        public enum ResponseParamsTypes
        {
            Username,
            Name,
            documentId,
            Title,
            Access,
            State,
            ErrorCode,
            Category,
            Type,
            OrgDocType,
            OrgDocName,
            Origin,
            Language,
            PageCount,
            PublishDate,
            Description,
            Tags,
            Warnings,
            Folders
        }

        public enum ResponseParamsFolderTypes
        {
            FolderId,
            Username,
            Name,
            Description,
            Items,
            Created
        }
        #endregion


        public class IssuuDoc
        {
            //based on: http://issuu.com/services/api/issuu.document.list.html

            public IssuuDoc()
            {}

            public string Access { get; set; }
            public string Description { get; set; }
            public string DocumentId { get; set; }
            public List<string> Folders { get; set; }
            public string Name { get; set; }
            public string OrgDocName { get; set; }
            public string OrgDocType { get; set; }
            public string Origin { get; set; }
            public string PageCount { get; set; }
            public string PublishDate { get; set; }
            public string State { get; set; }
            public List<string> Tags { get; set; }
            public string Title { get; set; }
            public string Type { get; set; }
            public string Username { get; set; }
            public string ViewCount { get; set; }
        }

        public class IssuuFolder
        {
            //based on: http://www.issuu.com/services/api/issuu.folder.list.html

            public IssuuFolder()
            {}

            public string FolderId { get; set; }
            public string Username { get; set; }
            public string Name { get; set; }
            public string Description { get; set; }
            public int Items { get; set; }
            public string Created { get; set; }
        }
    }
}